/**
 * Created by zhang on 2015/11/2.
 */

//1 回调   this指向函数 执行时的当前对象，而非声明环境

function foo()
{
    console.info(this);
    console.log(this.a);
}

function doFoo(fn)
{
    fn();
}

function doFoo2(o)
{
    o.foo();
}

var obj = { a:2,foo:foo};
var a = "I am an a";

doFoo2(obj);

doFoo(obj.foo);

//2 apply   apply、call、bind都有个作用就是改变作用域，这里用apply将foo函数的作用域指向obj对象，同时传入参数。

function foo2(sth)
{
    console.log(this.a,sth);
}

function bind(fn,obj)
{
    return function()
    {
        return fn.apply(obj,arguments);   //执行bind函数的时候返回的是一个匿名函数
    }
}
var obj = {a:2};
var bar = bind(foo2,obj);
var b = bar(3);  //返回的是之前传入的foo2函数的执行结果
console.log(b);

//3 new   bind函数的第一个参数为null代表作用域不变，后面的不定参数将会和函数本身的参数按次序进行绑定，绑定之后执行函数只能从未绑定的参数开始传值。
function foo3(a,b)
{
    this.val = a+b;
}
var bar = foo3.bind(null,'p1');
var baz = new bar('p2');
console.log(baz.val);

//4 自执行函数   创建一个立即执行的函数同时避免污染全局变量

function foo4()
{
    console.log(this.a);
}
var a = 2;var o={a:3,foo:foo};var p={a:4};
//(p.foo4=o.foo4)();

//5 变量属性   当一个变量被声明后，扩充其属性并不会改变原数据类型。
var a =[];
a[0] = 1;
a['foobar'] = 2;
console.log(a);
console.log(a.foobar);

//6 精度问题  当操作小数时请小心，js的小数计算并不精确，所以上面的判断是false。字符串变量是常量。
var a = 'foo';
a[1] = '0';
console.log(0.1 + 0.2 == 0.3 && a );

//7 命名提升 声明的变量和命名函数都会被提升到代码的最前面，只不过声明的变量的赋值语句在代码中的位置不变

foo7();
var foo7 = 0;
function foo7()
{
    console.log(1);
}
foo7 = function()
{
    console.log(2);
};

//等价于  下面的代码
//var foo;
//function foo(){}
//foo();
//foo = 0;
//foo = function(){};

//8 作用域  javascript并不是以代码段为作用域，而是以函数。再根据命名提升的原则
foo8();
var a = false;
if(a)
{
    function foo8()
    {
        console.log('a1');
    }
}else{
    function foo8()
    {
        console.log('b1');
    }
}
//等价于
//function foo(){console.log('a');}
//function foo(){console.log('b');}
//foo();
//var a = true;
//if(a){}else{}

//9 闭包陷阱 在内层函数引用外层函数定义的变量时，外层函数的变量不会被会被持久化。
for(var i=1; i<=5;i++)
{
    setTimeout(function(){
        console.log(i);
    },i*1000);
}

//10 伪闭包 闭包是函数的嵌套定义，而不是函数的嵌套调用。

function foo10()
{
    console.log(a);
}
function bar10()
{
    var a = 3;
    foo10();
}
var a = 2;
bar10();